/*
 * Copyright (c) 2018-2999 湖南洛云网络科技有限公司 All rights reserved.
 *
 * https://www.gz-yami.com/
 *
 */

package com.yami.shop.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.microsoft.schemas.office.visio.x2012.main.PageType;
import com.yami.shop.bean.dto.FlowPageAnalysisDto;
import com.yami.shop.bean.dto.PageAnalysisDto;
import com.yami.shop.bean.enums.FlowLogPageEnum;
import com.yami.shop.bean.enums.FlowVisitEnum;
import com.yami.shop.bean.model.*;
import com.yami.shop.bean.param.FlowAnalysisParam;
import com.yami.shop.bean.param.PageAnalysisParam;
import com.yami.shop.bean.param.ProdAnalysisSurveyParam;
import com.yami.shop.bean.param.VisitorTopParam;
import com.yami.shop.common.config.Constant;
import com.yami.shop.common.i18n.I18nMessage;
import com.yami.shop.common.util.Arith;
import com.yami.shop.common.util.PageParam;
import com.yami.shop.dao.FlowPageAnalysisMapper;
import com.yami.shop.service.*;
import lombok.AllArgsConstructor;
import ma.glasnost.orika.MapperFacade;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 流量分析—页面数据统计表
 *
 * @author YXF
 * @date 2020-07-14 11:26:35
 */
@Service
@AllArgsConstructor
public class FlowPageAnalysisServiceImpl extends ServiceImpl<FlowPageAnalysisMapper, FlowPageAnalysis> implements FlowPageAnalysisService {

    private final FlowPageAnalysisMapper flowPageAnalysisMapper;

    private final FlowPageAnalyseUserService flowPageAnalyseUserService;

    private final FlowUserAnalysisService flowUserAnalysisService;

    private final FlowLogService flowLogService;

    private final MapperFacade mapperFacade;

    private final OrderService orderService;

    private final ProductService productService;

    @Override
    public void getPageDataByLog(Map<String, List<FlowLog>> flowLogMap, Date startTime, Map<String, FlowUserAnalysis> flowUserAnalysisMap) {
        Map<String, Map<Integer, PageAnalysisParam>> map = statisticalData(flowLogMap,startTime,flowUserAnalysisMap);
        //插入统计的数据到数据库中-页面数据
        mapAsList(map.get("pageAnalysisMap"),1, startTime);
        //插入统计的数据到数据库中-商品详情页面数据
        mapAsList(map.get("prodPageAnalysisMap"),2, startTime);
    }

    @Override
    public IPage<PageAnalysisDto> getPageOrProdAnalysis(PageParam<PageAnalysisDto> page, FlowAnalysisParam flowAnalysisParam) {
        flowAnalysisParam.setTime(1);
        PageParam<PageAnalysisDto> pageOrProdAnalysis = new PageParam<PageAnalysisDto>();
        if (flowAnalysisParam.getTimeType() != 4){
            //获取数据
            pageOrProdAnalysis = flowPageAnalysisMapper.getPageOrProdAnalysis(page, flowAnalysisParam);
        }else {
            //实时数据
            pageOrProdAnalysis.setSize(page.getSize());
            pageOrProdAnalysis.setCurrent(page.getCurrent());
            pageOrProdAnalysis.setRecords(Lists.newArrayList());
            //统计实时数据
            statisticalPageOrProdInfoData(flowAnalysisParam, pageOrProdAnalysis);
        }
        // 商品详情页数据
        Map<String, String> prodMap = null;
        if (flowAnalysisParam.getPageType().equals(2)) {
            Set<Long> prodIds = pageOrProdAnalysis.getRecords().stream()
                    .filter(p->StrUtil.isNotBlank(p.getBizDate()))
                    .map(p -> Long.valueOf(p.getBizDate()))
                    .collect(Collectors.toSet());
            List<Product> productList = productService.getProductListBySpuIds(prodIds);
            prodMap = productList.stream().collect(Collectors.toMap(p ->String.valueOf(p.getProdId()), p -> p.getProdName()));
        }

        List<PageAnalysisDto> records = pageOrProdAnalysis.getRecords();
        for (PageAnalysisDto pageAnalysisDto:records){
            if (flowAnalysisParam.getPageType().equals(2)) {
                pageAnalysisDto.setPageName(prodMap.get(pageAnalysisDto.getBizDate()));
            } else {
                pageAnalysisDto.setPageName(FlowLogPageEnum.name(pageAnalysisDto.getPageId()));
            }
            pageAnalysisDto.setAverageStopTime(Arith.div(pageAnalysisDto.getStopTime().doubleValue(),pageAnalysisDto.getVisitUser().doubleValue(),2));
            pageAnalysisDto.setClickRate(Arith.div(pageAnalysisDto.getClickUser().doubleValue(),pageAnalysisDto.getVisitUser().doubleValue(),2));
            pageAnalysisDto.setVisitToPayRate(Arith.div(pageAnalysisDto.getPayUser().doubleValue(),pageAnalysisDto.getVisitUser().doubleValue(),2));
            pageAnalysisDto.setVisitToPlaceOrderRate(Arith.div(pageAnalysisDto.getPlaceOrderUser().doubleValue(),pageAnalysisDto.getVisitUser().doubleValue(),2));
        }

        return pageOrProdAnalysis;
    }

    @Override
    public IPage<VisitorTopParam> getVisitorTop(IPage<FlowPageAnalysis> page, ProdAnalysisSurveyParam prodAnalysisSurveyParam) {
        return flowPageAnalysisMapper.getVisitorTop(page, prodAnalysisSurveyParam, I18nMessage.getDbLang());
    }

    /**
     *
     * @param flowAnalysisParam
     * @param pageOrProdAnalysis
     */
    private void statisticalPageOrProdInfoData(FlowAnalysisParam flowAnalysisParam, IPage<PageAnalysisDto> pageOrProdAnalysis) {
        Date beginTime = DateUtil.beginOfDay(new Date());
        //缓存中获取当天数据
        List<FlowLog> flowLogList = flowLogService.getFlowLogListByCache();
        if (!flowAnalysisParam.getSystemType().equals(0)){
            flowLogList = flowLogList.stream().filter(f -> f.getSystemType().equals(flowAnalysisParam.getSystemType())).collect(Collectors.toList());
        }
        //Map<uuidSession, List<FlowLog>>
        Map<String, List<FlowLog>> flowAnalysisLogMap = flowLogList.stream().collect(Collectors.groupingBy(FlowLog::getUuidSession));
        /*
            统计页面数据
            Map<pageAnalysisMap, Map<Integer, PageAnalysisParam>> 页面数据
            Map<prodPageAnalysisMap, Map<Integer, PageAnalysisParam>> 商品详情页数据
         */
        Map<String, Map<Integer, PageAnalysisParam>> map = statisticalData(flowAnalysisLogMap, beginTime,null);
        List<FlowPageAnalysisDto> flowPageAnalysisDtoList = Lists.newArrayList();
        //页面数据统计
        if (flowAnalysisParam.getPageType().equals(1)){
            //Map<系统类型, PageAnalysisParam>
            Map<Integer, PageAnalysisParam> pageAnalysisMap = map.get("pageAnalysisMap");
            Map<Integer, FlowPageAnalysisDto> flowPageAnalysisDtoMap = new HashMap<>(16);
            //处理流程：循环系统类型 -》 循环页面集合
            //循环系统类型
            for (PageAnalysisParam pageAnalysisParam:pageAnalysisMap.values()){
                //循环页面集合
                for (FlowPageAnalysisDto flowPageAnalysisDto:pageAnalysisParam.getPageAnalysisMap().values()){
                    if (!flowPageAnalysisDtoMap.containsKey(flowPageAnalysisDto.getPageId())){
                        flowPageAnalysisDtoMap.put(flowPageAnalysisDto.getPageId(),flowPageAnalysisDto);
                        flowPageAnalysisDtoList.add(flowPageAnalysisDto);
                    }else {
                        flowPageAnalysisDtoMap.get(flowPageAnalysisDto.getPageId()).statisticalData(flowPageAnalysisDto);
                    }
                }
            }
        }
        //商品详情页数据统计
        else if(flowAnalysisParam.getPageType().equals(2)){
            //Map<系统类型, PageAnalysisParam>
            Map<Integer, PageAnalysisParam> prodPageAnalysisMap = map.get("prodPageAnalysisMap");
            //Map<商品类型, Map<商品id, FlowPageAnalysisDto>>
            Map<Integer, Map<String, FlowPageAnalysisDto>> flowProdInfoPageAnalysisDtoMap = new HashMap<>(16);
            //处理流程：循环系统类型 -》 循环商品类型 -》 循环商品id集合
            //循环系统类型
            for (PageAnalysisParam pageAnalysisParam:prodPageAnalysisMap.values()){
                //循环商品类型
                for (Integer prodType:pageAnalysisParam.getProdPageAnalysisMap().keySet()){
                    if (!flowProdInfoPageAnalysisDtoMap.containsKey(prodType)){
                        flowProdInfoPageAnalysisDtoMap.put(prodType, new HashMap<>(16));
                    }
                    Map<String, FlowPageAnalysisDto> flowPageAnalysisDtoByProdType = flowProdInfoPageAnalysisDtoMap.get(prodType);
                    //循环商品id集合
                    for (FlowPageAnalysisDto flowPageAnalysisDto:flowPageAnalysisDtoByProdType.values()){
                        if (!flowPageAnalysisDtoByProdType.containsKey(flowPageAnalysisDto.getPageId())){
                            flowPageAnalysisDtoList.add(flowPageAnalysisDto);
                            flowPageAnalysisDtoByProdType.put(flowPageAnalysisDto.getBizDate(), flowPageAnalysisDto);
                        }else {
                            flowPageAnalysisDtoByProdType.get(flowPageAnalysisDto.getPageId()).statisticalData(flowPageAnalysisDto);
                        }
                    }
                }
            }
        }
        //排序
        if (flowAnalysisParam.getPageType().equals(1)){
            flowPageAnalysisDtoList.sort(Comparator.comparing(FlowPageAnalysisDto::getClick));
        }else{
            flowPageAnalysisDtoList.sort(Comparator.comparing(FlowPageAnalysisDto::getBizDate));
        }
        /*
            分页
            start：开始的索引
            end：结束的索引
         */
        Long start = (pageOrProdAnalysis.getCurrent() - 1) * pageOrProdAnalysis.getSize();
        Long end = pageOrProdAnalysis.getSize() * pageOrProdAnalysis.getCurrent();
        //转化对象类型，并处理\写入数据
        for (int i= 0;i<flowPageAnalysisDtoList.size();i++){
            PageAnalysisDto pageAnalysisDto = mapAsPageAnalysisDto(flowPageAnalysisDtoList.get(i));
            pageAnalysisDto.setPageName(FlowLogPageEnum.name(pageAnalysisDto.getPageId()));
            if (start <= i && end > i){
                pageOrProdAnalysis.getRecords().add(pageAnalysisDto);
            }
        }
        pageOrProdAnalysis.setTotal(flowPageAnalysisDtoList.size());
        pageOrProdAnalysis.setSize(pageOrProdAnalysis.getSize());
    }

    /**
     * 转换对象类型
     * @param flowPageAnalysisDto
     * @return
     */
    private PageAnalysisDto mapAsPageAnalysisDto(FlowPageAnalysisDto flowPageAnalysisDto) {
        PageAnalysisDto pageAnalysisDto = new PageAnalysisDto(flowPageAnalysisDto.getPageId(),flowPageAnalysisDto.getBizDate());
        pageAnalysisDto.setVisis(flowPageAnalysisDto.getVisis());
        pageAnalysisDto.setVisitUser(flowPageAnalysisDto.getVisitUser().size());
        pageAnalysisDto.setClick(flowPageAnalysisDto.getClick());
        pageAnalysisDto.setClickUser(flowPageAnalysisDto.getClickUser().size());
        pageAnalysisDto.setShareVisit(flowPageAnalysisDto.getShareVisit());
        pageAnalysisDto.setShareVisitUser(flowPageAnalysisDto.getShareVisitUser().size());
        pageAnalysisDto.setPlaceOrderAmount(flowPageAnalysisDto.getPlaceOrderAmount());
        pageAnalysisDto.setPlaceOrderUser(flowPageAnalysisDto.getPlaceOrderUser().size());
        pageAnalysisDto.setPayAmount(flowPageAnalysisDto.getPayAmount());
        pageAnalysisDto.setPayUser(flowPageAnalysisDto.getPayUser().size());
        return pageAnalysisDto;
    }

    /**
     * 统计页面\商品详情页数据
     * @param flowLogMap 数据
     * @param startTime 开始时间
     * @param flowUserAnalysisMap 用户统计数据储存集合
     * @return
     */
    private Map<String, Map<Integer, PageAnalysisParam>> statisticalData(Map<String, List<FlowLog>> flowLogMap, Date startTime, Map<String, FlowUserAnalysis> flowUserAnalysisMap){
        // key:系统类型
        Map<Integer, PageAnalysisParam> pageAnalysisMap = new HashMap<Integer, PageAnalysisParam>(16);
        Map<Integer, PageAnalysisParam> prodPageAnalysisMap = new HashMap<Integer, PageAnalysisParam>(16);
        Set<String> keySet = flowLogMap.keySet();
        Integer systemType = 0;
        //循环会话
        for (String key:keySet){
            //获取用户会话记录
            List<FlowLog> flowLogList = flowLogMap.get(key);
            //根据页面编号进行分组，用于页面数据的统计
            Map<Integer, List<FlowLog>> flowAnalysisLogListToPageId = flowLogList.stream().collect(Collectors.groupingBy(FlowLog::getPageId));
            //获取用户会话记录中的页面访问和分享记录，用于添加页面结束时间以及获取用户访问过的页面集合
            List<FlowLog> pageList = flowLogList.stream().filter(flowAnalysisLog -> FlowVisitEnum.isVisitOrShare(flowAnalysisLog.getVisitType())).collect(Collectors.toList());
            pageList.sort(Comparator.comparingInt(FlowLog::getStep).reversed());
            //pageSet：获取用户访问过页面的编号集合
            Set<Integer> pageSet = new HashSet<>();
            //获取所有的订单编号
            Set<String> orderNumberSet = new HashSet<>();
            /*
             1.nextDate 获取页面的结束时间（结束时间 = 下个访问的页面的创建时间，用于页面数据统计时的停留时间统计
             2.pageSet 获取用户访问过的页面编号，用于页面数据统计时，循环的key
             3.step 获取页面对应的下一步骤页面的页面编号,用于页面路径时的数据处理
             4.systemType 系统类型 1:pc  2:h5  3:小程序 4:安卓  5:ios
             */
            Date nextDate = null;
            Integer nextPageId = null;
            for (int i = 0;i<pageList.size();i++){
                if (i == 0){
                    //最后一个步骤的值设为初始值，往前面的步骤赋值
                    FlowLog flowLogEnd = pageList.get(0);
                    nextDate = flowLogEnd.getCreateTime();
                    nextPageId = flowLogEnd.getPageId();
                    systemType = flowLogEnd.getSystemType();
                    flowLogEnd.setEndTime(nextDate);
                    flowLogEnd.setStopTime(1L);
                    pageSet.add(flowLogEnd.getPageId());
                    continue;
                }
                FlowLog flowLog = pageList.get(i);
                //当前页面的结束时间为下个访问的页面的创建时间
                flowLog.setEndTime(nextDate);
                flowLog.setNextPageId(nextPageId);
                //更新为当前的创建时间，作为上一步操作的endTime(结束时间)
                nextDate = flowLog.getCreateTime();
                //更新为当前的页面编号，作为上一步操作的nextPageId（该页面跳转的下个页面,存储的下个页面的编号）
                nextPageId = flowLog.getPageId();
                //页面编号添加到集合
                pageSet.add(flowLog.getPageId());
                Boolean isPlaceOrPay = (flowLog.getPageId().equals(FlowLogPageEnum.PAY.value()) ||
                        flowLog.getPageId().equals(FlowLogPageEnum.PAY_SUCCESS.value())) && StrUtil.isNotBlank(flowLog.getBizData());
                if (isPlaceOrPay){
                    orderNumberSet.addAll(Arrays.asList(flowLog.getBizData().split(",")));
                }
            }
            //页面数据统计
            FlowPageAnalysisDto flowPageAnalysisDto = null;
            updateMap(pageAnalysisMap, systemType);
            Map<Integer, FlowPageAnalysisDto> pageAnalysisAsSystemType = pageAnalysisMap.get(systemType).getPageAnalysisMap();
            for (Integer pageId:pageSet){
                //判断是否存在该页面的对象，如果不存在就创建一个新对象，存在则从集合中读取
                if (!pageAnalysisAsSystemType.containsKey(pageId)){
                    flowPageAnalysisDto = new FlowPageAnalysisDto();
                    flowPageAnalysisDto.setPageId(pageId);
                    flowPageAnalysisDto.setType(1);
                    flowPageAnalysisDto.setSystemType(systemType);
                    pageAnalysisAsSystemType.put(pageId, flowPageAnalysisDto);
                }
                flowPageAnalysisDto = pageAnalysisAsSystemType.get(pageId);
                //遍历用户会话中该页面的所有操作记录，统计页面数据
                for (FlowLog flowLog :flowAnalysisLogListToPageId.get(pageId)){
                    if (flowLog.getPageId().equals(pageId)){
                        this.statisticalFlowPageAnalysisData(flowLog, flowPageAnalysisDto);
                    }
                }
            }
            updateMap(prodPageAnalysisMap, systemType);
            //获取该用户登陆系统类型的
            Map<Integer, Map<String, FlowPageAnalysisDto>> prodPageAnalysisAsSystemType = prodPageAnalysisMap.get(systemType).getProdPageAnalysisMap();
            //统计商品详情页面的分析数据
            this.statisticalProdPageData(flowAnalysisLogListToPageId, prodPageAnalysisAsSystemType, systemType);
            //页面记录按用户的操作步骤正序
            pageList.sort(Comparator.comparingInt(FlowLog::getStep));
            //页面统计下单、支付信息
            this.statisticalPlaceOrPayDate(pageList, pageAnalysisAsSystemType, prodPageAnalysisAsSystemType, orderNumberSet,flowUserAnalysisMap);
        }
        Map<String, Map<Integer, PageAnalysisParam>> map = new HashMap<>(16);
        map.put("pageAnalysisMap",pageAnalysisMap);
        map.put("prodPageAnalysisMap",prodPageAnalysisMap);
        return  map;
    }


    /**
     * 商品详情页数据统计
     * @param flowAnalysisLogListToPageId 商品详情页记录信息
     * @param prodInfoMap 统计的商品详情页信息
     */
    private void statisticalProdPageData(Map<Integer, List<FlowLog>> flowAnalysisLogListToPageId, Map<Integer, Map<String, FlowPageAnalysisDto>> prodInfoMap,
                                         Integer systemType){
        //循环商品详情页面中的数据
        List<Integer> prodInfoPageList = Lists.newArrayList();
        prodInfoPageList.add(FlowLogPageEnum.PROD_INFO.value());
        prodInfoPageList.add(FlowLogPageEnum.PROD_INFO_SECKILL.value());
        prodInfoPageList.add(FlowLogPageEnum.PROD_INFO_GROUP_BUG.value());
        FlowPageAnalysisDto flowAnalysisProd = null;
        for (Integer prodInfoKey:prodInfoPageList){
            if (!flowAnalysisLogListToPageId.containsKey(prodInfoKey)){
                continue;
            }
            //根据商品id分组
            Map<String, List<FlowLog>> prodMap = flowAnalysisLogListToPageId.get(prodInfoKey).stream().filter(f->StrUtil.isNotBlank(f.getBizData())).collect(Collectors.groupingBy(FlowLog::getBizData));
            //获取ProdId数组
            Map<String, Long> prodIdMap = getProdIdMap(prodMap.keySet());
            //商品类型 0普通  1团购 2秒杀
            Integer prodType = FlowLogPageEnum.getProdType(prodInfoKey);
            //商品信息Map
            Map<String, FlowPageAnalysisDto> flowToProdIdMap = null;
            if (!prodInfoMap.containsKey(prodType)){
                prodInfoMap.put(prodType,new HashMap<>(16));
            }
            flowToProdIdMap = prodInfoMap.get(prodType);
            for(String prodId:prodMap.keySet()){
                // 判断是否存在该页面的对象，如果不存在则创建一个新对象
                if (!flowToProdIdMap.containsKey(prodId)){
                    flowAnalysisProd = new FlowPageAnalysisDto();
                    flowAnalysisProd.setPageId(prodInfoKey);
                    flowAnalysisProd.setBizDate(prodId);
                    flowAnalysisProd.setBizType(FlowLogPageEnum.getProdType(prodInfoKey));
                    flowAnalysisProd.setType(2);
                    flowAnalysisProd.setSystemType(systemType);
                    flowAnalysisProd.setShopId(Objects.nonNull(prodIdMap.get(prodId))?prodIdMap.get(prodId): Constant.PLATFORM_SHOP_ID);
                    flowToProdIdMap.put(prodId,flowAnalysisProd);
                }
                flowAnalysisProd = flowToProdIdMap.get(prodId);
                //循环用户会话记录，统计数据
                for (FlowLog flowLog :prodMap.get(prodId)){
                    this.statisticalFlowPageAnalysisData(flowLog,flowAnalysisProd);
                }
            }
        }
    }

    private Map<String, Long> getProdIdMap(Set<String> prodSet) {
        Set<Long> prodIdSet = prodSet.stream().map(p -> Long.parseLong(p)).collect(Collectors.toSet());
        if (CollectionUtil.isEmpty(prodIdSet)) {
            return new HashMap<>(16);
        }
        List<Product> prodIdListDb = productService.list(new LambdaQueryWrapper<Product>().in(Product::getProdId, prodIdSet));
        Map<String, Long> prodIdMap = new HashMap<>(16);
        for (Product product:prodIdListDb){
            prodIdMap.put(String.valueOf(product.getProdId()),product.getShopId());
        }
        return prodIdMap;
    }


    /**
     * 统计数据(点击、访问、分享、停留时长)
     * @param flowLog 用户操作记录
     * @param flowPageAnalysisDto 页面统计数据
     */
    private void statisticalFlowPageAnalysisData(FlowLog flowLog, FlowPageAnalysisDto flowPageAnalysisDto){
        //根据访问类型统计数据
        if (flowLog.getVisitType().equals(FlowVisitEnum.VISIT.value())){
            //商品访问次数
            flowPageAnalysisDto.setVisis(flowPageAnalysisDto.getVisis() + 1);
            //访问用户数
            flowPageAnalysisDto.getVisitUser().add(flowLog.getUuid());
        }else if (flowLog.getVisitType().equals(FlowVisitEnum.SHARE.value())){
            //分享访问次数
            flowPageAnalysisDto.setShareVisit(flowPageAnalysisDto.getShareVisit() + 1);
            //分享访问人数
            flowPageAnalysisDto.getShareVisitUser().add(flowLog.getUuid());
        }else if (flowLog.getVisitType().equals(FlowVisitEnum.CLICK.value())){
            //商品页点击数
            flowPageAnalysisDto.setClick(flowPageAnalysisDto.getClick() + flowLog.getNums());
            //商品页点击人数
            flowPageAnalysisDto.getClickUser().add(flowLog.getUuid());
        }else if (flowLog.getVisitType().equals(FlowVisitEnum.SHOP_CAT.value())){
            //加购数
            flowPageAnalysisDto.setPlusShopCart(flowPageAnalysisDto.getPlusShopCart() +  + flowLog.getNums());
            //加购人数
            flowPageAnalysisDto.getPlusShopCartUser().add(flowLog.getUuid());
        }
        if (FlowVisitEnum.isVisitOrShare(flowLog.getVisitType())){
            //停留时长（秒）
            Long stopTime = this.countStopTime(flowLog.getCreateTime(), flowLog.getEndTime());
            flowLog.setStopTime(stopTime);
            flowPageAnalysisDto.setStopTime(stopTime + flowPageAnalysisDto.getStopTime());
        }
    }

    /**
     * 统计数据(下单、支付)
     * @param pageList 访问/分享页面列表
     * @param flowAnalysisPageMap 统计的页面数据
     * @param prodInfoMap 统计的商品详情页面数据
     * @param orderNumberSet 用户下单及支付订单编号集合
     * @param flowUserAnalysisMap 用户数据统计集合
     */
    private void statisticalPlaceOrPayDate(List<FlowLog> pageList, Map<Integer, FlowPageAnalysisDto> flowAnalysisPageMap, Map<Integer, Map<String,
            FlowPageAnalysisDto>> prodInfoMap, Set<String> orderNumberSet, Map<String, FlowUserAnalysis> flowUserAnalysisMap){
        if (orderNumberSet.size() == 0){
            return;
        }
        Integer placeStep = 0;
        Integer payStep = 0;
        FlowPageAnalysisDto flowPageAnalysisDto = null;
        List<Order> orderList = orderService.getOrderAndOrderItemByOrderNumberList(orderNumberSet);
        Map<String, Order> orderMap = orderList.stream().collect(Collectors.toMap(Order::getOrderNumber, order -> order));
        //统计下单金额和支付金额
        for (int i= 0;i<pageList.size();i++){
            FlowLog pageLogData = pageList.get(i);
            Boolean isPay = (pageLogData.getPageId().equals(FlowLogPageEnum.PAY.value()) || pageLogData.getPageId().equals(FlowLogPageEnum.PAY_SUCCESS.value()))
                    && StrUtil.isNotBlank(pageLogData.getBizData());
            if (isPay) {
                String[] orderNumbers = pageLogData.getBizData().split(",");
                for (String orderNumber : orderNumbers) {
                    Order order = orderMap.get(orderNumber);
                    if(Objects.isNull(order)){
                        continue;
                    }
                    //统计页面下单和支付数据  #START
                    //保存已进行过数据统计的页面的集合
                    Set<Integer> pageIdSet = new HashSet<>();
                    FlowLog pageLog = null;
                    if (pageLogData.getPageId().equals(FlowLogPageEnum.PAY.value())) {
                        // 页面下单数据
                        for (int p = placeStep; p <= i; p++) {
                            pageLog = pageList.get(p);
                            // 已进行过数据统计操作的页面，无需再次数据统计
                            if (pageIdSet.contains(pageLog.getPageId())) {
                                continue;
                            }
                            flowPageAnalysisDto = flowAnalysisPageMap.get(pageLog.getPageId());
                            flowPageAnalysisDto.setPlaceOrderAmount(Arith.add(flowPageAnalysisDto.getPlaceOrderAmount(), order.getActualTotal()));
                            flowPageAnalysisDto.getPlaceOrderUser().add(pageLogData.getUuid());
                            pageIdSet.add(pageLog.getPageId());
                        }
                        placeStep = i + 1;
                    } else {
                        // 页面支付数据
                        for (int p = payStep; p < i; p++) {
                            pageLog = pageList.get(p);
                            // 已进行过数据统计操作的页面，无需再次数据统计
                            if (pageIdSet.contains(pageLog.getPageId())) {
                                continue;
                            }
                            flowPageAnalysisDto = flowAnalysisPageMap.get(pageLog.getPageId());
                            flowPageAnalysisDto.setPayAmount(Arith.add(flowPageAnalysisDto.getPayAmount(), order.getActualTotal()));
                            flowPageAnalysisDto.getPayUser().add(pageLogData.getUuid());
                            pageIdSet.add(pageLog.getPageId());
                        }
                        payStep = i + 1;
                    }
                    if(Objects.nonNull(flowUserAnalysisMap)){
                        //统计用户下单/支付金额
                        flowUserAnalysisService.statisticalPlaceOrderOrPayData(pageLogData, order, flowUserAnalysisMap);
                    }
                    //统计页面下单和支付数据  #END

                    // 商品详情页数据统计  #START
                    if (!prodInfoMap.containsKey(order.getOrderType())){
                        continue;
                    }
                    Map<String, FlowPageAnalysisDto> flowAnalysisPageDtoMap = prodInfoMap.get(order.getOrderType());
                    for (OrderItem orderItem:order.getOrderItems()){
                        if (!flowAnalysisPageDtoMap.containsKey(String.valueOf(orderItem.getProdId()))){
                            continue;
                        }
                        flowPageAnalysisDto = flowAnalysisPageDtoMap.get(String.valueOf(orderItem.getProdId()));
                        if (pageLogData.getPageId().equals(FlowLogPageEnum.PAY.value())){
                            flowPageAnalysisDto.setPlaceOrderAmount(Arith.add(flowPageAnalysisDto.getPlaceOrderAmount(), orderItem.getActualTotal()));
                            flowPageAnalysisDto.getPlaceOrderUser().add(pageLogData.getUuid());
                        }else {
                            flowPageAnalysisDto.setPayAmount(Arith.add(flowPageAnalysisDto.getPayAmount(), orderItem.getActualTotal()));
                            flowPageAnalysisDto.getPayUser().add(pageLogData.getUuid());
                        }
                    }
                    // 商品详情页数据统计  #END
                }
            }
        }
    }


    /**
     * 计算页面停留时间
     * @param startTime
     * @param endTime
     * @return
     */
    private Long countStopTime(Date startTime, Date endTime){
        Long stopTime = 1L;
        if (Objects.isNull(startTime) || Objects.isNull(endTime)){
            return stopTime;
        }
        long time = endTime.getTime() - startTime.getTime();
        if (time<1000){
            return stopTime;
        }
        return stopTime/1000;
    }

    /**
     * Map中统计的数据转化为List
     * @param pageAnalysisMap 页面统计数据
     * @param type   1:页面统计  2:商品详情页统计
     * @param startTime  统计的开始时间
     */
    private void mapAsList(Map<Integer, PageAnalysisParam> pageAnalysisMap, Integer type,Date startTime) {
        //页面统计数据后存放的集合
        List<FlowPageAnalysisDto> flowPageAnalysisDtoList = Lists.newArrayList();
        //商品详情页统计数据后存放的集合
        List<FlowPageAnalysis> flowPageAnalysisList = Lists.newArrayList();

        if (type == 1){
            //页面数据
            Integer index = 0;
            for (Integer systemType:pageAnalysisMap.keySet()){
                Map<Integer, FlowPageAnalysisDto> flowAnalysisPageMap = pageAnalysisMap.get(systemType).getPageAnalysisMap();
                Iterator<FlowPageAnalysisDto> iterator = flowAnalysisPageMap.values().iterator();
                while (iterator.hasNext()){
                    FlowPageAnalysisDto flowPageAnalysisDto = iterator.next();
                    FlowPageAnalysis flowPageAnalysis = mapperFacade.map(flowPageAnalysisDto, FlowPageAnalysis.class);
                    flowPageAnalysis.setCreateDate(startTime);
                    //页面用户数据项
                    flowPageAnalysisList.add(flowPageAnalysis);
                    flowPageAnalysisDtoList.add(flowPageAnalysisDto);
                }
            }
        }else if (type == 2){
            //商品详情页数据
            for (Integer systemType: pageAnalysisMap.keySet()){
                Map<Integer, Map<String, FlowPageAnalysisDto>> prodPageAnalysisMap = pageAnalysisMap.get(systemType).getProdPageAnalysisMap();
                for (Integer prodType: prodPageAnalysisMap.keySet()){
                    Map<String, FlowPageAnalysisDto> flowAnalysisPageDtoMap = prodPageAnalysisMap.get(prodType);
                    for (String prodId: flowAnalysisPageDtoMap.keySet()){
                        FlowPageAnalysisDto flowPageAnalysisDto = flowAnalysisPageDtoMap.get(prodId);
                        FlowPageAnalysis flowPageAnalysis = mapperFacade.map(flowPageAnalysisDto, FlowPageAnalysis.class);
                        flowPageAnalysis.setCreateDate(startTime);
                        flowPageAnalysisList.add(flowPageAnalysis);
                        flowPageAnalysisDtoList.add(flowPageAnalysisDto);
                    }
                }
            }
        }
        //批量保存
        saveBatch(flowPageAnalysisList);
        flowPageAnalyseUserService.insertBatch(flowPageAnalysisList,flowPageAnalysisDtoList);
    }

    /**
     * 获取页面的点击次数
     * @param clickLogList 点击记录列表
     * @param pageId 页面编号
     * @param type 0：通用页面  1：商品详情页面
     * @return
     */
    private Integer getPageClickNums(List<FlowLog> clickLogList, Integer pageId, Integer type, String bizData){
        Integer clickNums = 0;
        for (FlowLog flowLog :clickLogList){
            if (flowLog.getPageId().equals(pageId)&& type.equals(0)){
                clickNums++;
            }
            if (flowLog.getPageId().equals(pageId) && type.equals(1) ){
                String bizDataDb = flowLog.getBizData();
                if (Objects.equals(bizDataDb,bizData)){
                    clickNums++;
                }
            }
        }
        return clickNums;
    }

    private void updateMap(Map<Integer, PageAnalysisParam> map, Integer systemType){
        if (!map.containsKey(systemType)){
            PageAnalysisParam pageAnalysisParam = new PageAnalysisParam();
            pageAnalysisParam.setSystemType(systemType);
            map.put(systemType,pageAnalysisParam);
        }
    }
}
